/*
 *
 * Copyright 2019 Asylo authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#ifndef ASYLO_IDENTITY_ATTESTATION_SGX_INTERNAL_REMOTE_ASSERTION_GENERATOR_ENCLAVE_H_
#define ASYLO_IDENTITY_ATTESTATION_SGX_INTERNAL_REMOTE_ASSERTION_GENERATOR_ENCLAVE_H_

#include <memory>
#include <vector>

#include "asylo/crypto/certificate.pb.h"
#include "asylo/crypto/certificate_interface.h"
#include "asylo/crypto/signing_key.h"
#include "asylo/enclave.pb.h"
#include "asylo/identity/attestation/sgx/internal/remote_assertion_generator_enclave.pb.h"
#include "asylo/identity/attestation/sgx/internal/sgx_remote_assertion_generator_impl.h"
#include "asylo/trusted_application.h"
#include "asylo/util/mutex_guarded.h"
#include "asylo/util/status.h"
#include "include/grpcpp/grpcpp.h"

namespace asylo {
namespace sgx {

// An enclave that acts as the SGX remote assertion generator. It hosts an
// instance of the SgxRemoteAssertionGenerator gRPC service, which fulfills
// GenerateAssertion requests from authenticated, local SGX enclaves.
class RemoteAssertionGeneratorEnclave final : public TrustedApplication {
 public:
  RemoteAssertionGeneratorEnclave();

  // From TrustedApplication.

  Status Initialize(const EnclaveConfig &config) override;
  Status Run(const EnclaveInput &input, EnclaveOutput *output) override;
  Status Finalize(const EnclaveFinal &final_input) override;

 private:
  struct AttestationKeyCertsPair {
    // Used by the SgxRemoteAssertionGenerator service to produce assertions.
    std::unique_ptr<SigningKey> attestation_key;

    // Certificates that certify the signing key wielded by the
    // SgxRemoteAssertionGenerator service.
    std::vector<CertificateChain> certificate_chains;
  };

  struct ServerServicePair {
    // The gRPC server hosting the SgxRemoteAssertionGenerator service.
    std::unique_ptr<::grpc::Server> server;

    // The SgxRemoteAssertionGenerator service.
    std::unique_ptr<SgxRemoteAssertionGeneratorImpl> service;
  };

  // Starts the SgxRemoteAssertionGenerator gRPC server.
  Status StartRemoteAssertionGeneratorGrpcServer(
      const StartServerRequestInput &input);

  // Generates an SGX hardware REPORT that is suitable for use in the PCE's
  // GetPceInfo protocol.
  Status GeneratePceInfoSgxHardwareReport(
      const GeneratePceInfoSgxHardwareReportInput &input,
      GeneratePceInfoSgxHardwareReportOutput *output);

  // Generates a new value for |attestation_key_|. If TARGETINFO is specified in
  // |input|, this method also generates an SGX hardware REPORT that is suitable
  // for use in the PCE's SignReport protocol. This function can also be used to
  // generate certificate signing requests for certificate authorities.
  Status GenerateKeyAndCsr(const GenerateKeyAndCsrInput &input,
                           GenerateKeyAndCsrOutput *output);

  // Updates |certificate_chains_| with the provided certificate chains in
  // |input|, if valid for the current attestation key. If any of the provided
  // certificate chains are invalid, or not for the current attestation key,
  // then no certificate chains are updated. If the SgxRemoteAssertionGenerator
  // gRPC server is running, updates certificates and the attestation key used
  // by SgxRemoteAssertionGenerator service.
  //
  // This function is expected to be called after an attestation key is
  // generated by GenerateKeyAndCsr.
  Status UpdateCerts(const UpdateCertsInput &input, UpdateCertsOutput *output);

  // A guarded struct that holds attestation key and certificates.
  MutexGuarded<AttestationKeyCertsPair> attestation_key_certs_pair_;

  // A guarded struct that holds remote assertion generator server and remote
  // assertion generator service.
  MutexGuarded<ServerServicePair> server_service_pair_;

  const VerificationConfig verification_config_;

  std::string remote_assertion_generator_server_address_;
};

}  // namespace sgx
}  // namespace asylo

#endif  // ASYLO_IDENTITY_ATTESTATION_SGX_INTERNAL_REMOTE_ASSERTION_GENERATOR_ENCLAVE_H_
